import { promisify } from 'bluebird';
import { Controller } from 'egg';
import { createReadStream, stat } from 'fs';
import { TOTAL_QUESTION } from '../../constants/answer-progress-state';
import { Result } from '../util';

import { pageSizeCommonRule, uuidCommonRule, uuidContainAllRule } from './validate-rule';

class AnswerController extends Controller {
  async saveQuestionScore() {
    const { ctx } = this;

    ctx.validate({
      questionnaireUuid: uuidCommonRule,
      userUuid: uuidCommonRule,
      questionUuid: uuidCommonRule,
      score: {
        type: 'number'
      }
    }, ctx.request.body);

    const {
      questionnaireUuid,
      userUuid,
      questionUuid,
      score
    } = ctx.request.body;

    const result = await ctx.service.answer.saveQuestionScore(
      questionnaireUuid,
      userUuid,
      questionUuid,
      score
    );

    if (!result) {
      ctx.status = 500;
      ctx.body = new Result(undefined, '服务器内部错误');
      return;
    }

    ctx.body = new Result(result);
  }

  /**
   * 问卷反馈页面化
   */
  async feedback() {
    const { ctx } = this;
    ctx.validate({
      mergeUuid: uuidCommonRule,
    }, ctx.query);

    const { mergeUuid } = ctx.query;
    const statisticData = await ctx.service.answer.createStatisticData(mergeUuid);
    ctx.body = new Result(statisticData);
  }

  async downloadFeedbackDocx() {
    const { ctx } = this;
    ctx.validate({
      mergeUuid: uuidCommonRule,
      isView: {
        requrie: false,
        type: 'boolean'
      }
    }, ctx.query);

    const { mergeUuid, isView } = ctx.query;

    const filePath = await ctx.service.answer.createStatisticFile({
      mergeUuid,
      fileType: 'docx',
      isView: Boolean(isView) ?? false
    });
    ctx.body = new Result(filePath);

    const fileSize = (await promisify(stat)(filePath)).size.toString();
    ctx.attachment(filePath);
    ctx.set('Content-Length', fileSize);
    ctx.set('Content-Type', 'application/octet-stream');
    ctx.body = createReadStream(filePath);
  }

  /**
   * 发送邮件
   */
  async sendEmail() {
    const { ctx } = this;

    ctx.validate({
      mergeUuid: uuidCommonRule,
    }, ctx.request.body);

    const { mergeUuid } = ctx.request.body;

    const hasEmail = await ctx
      .service
      .answer
      .sendEmailByMergeUuid(mergeUuid);

    ctx.body = new Result({ hasEmail });
  }

  async searchList() {
    const { ctx } = this;

    ctx.validate({
      templateUuid: uuidContainAllRule,
      questionnaireUuid: uuidContainAllRule,
      page: {
        type: 'number'
      },
      pageSize: pageSizeCommonRule
    }, ctx.query);

    const {
      templateUuid,
      questionnaireUuid,
      page,
      pageSize
    } = ctx.query;

    const res = await ctx
      .service
      .answer
      .searchList(
        templateUuid,
        questionnaireUuid,
        Number(page),
        Number(pageSize)
      );

    ctx.body = new Result(res);
  }

  async downloadExcel() {
    const { ctx } = this;

    ctx.validate({
      templateUuid: uuidContainAllRule,
      questionnaireUuid: uuidContainAllRule,
    }, ctx.query);

    const { templateUuid, questionnaireUuid } = ctx.query;

    const filePath = await ctx
      .service
      .answer
      .downloadExcel(
        templateUuid,
        questionnaireUuid
      );
    const fileSize = (await promisify(stat)(filePath)).size.toString();

    ctx.attachment(filePath);
    ctx.set('Content-Length', fileSize);
    ctx.set('Content-Type', 'application/octet-stream');
    ctx.body = createReadStream(filePath);
  }

  async delete() {
    const { ctx } = this;

    ctx.validate({
      mergeUuid: uuidCommonRule
    }, ctx.request.body);

    const { mergeUuid } = ctx.request.body;

    const res = await ctx
      .service
      .answer
      .delete(mergeUuid);

    if (!res) {
      ctx.status = 422;
      ctx.body = new Result(undefined, '删除失败');
    }

    if (res) {
      ctx.body = new Result(undefined, '删除成功');
    }
  }

  // 获取分数列表
  async scoreList() {
    const { ctx } = this;

    ctx.validate({
      mergeUuid: uuidCommonRule,
    }, ctx.query);

    const { mergeUuid } = ctx.query;

    const scoreList = await ctx
      .service
      .answer
      .findAllScoreByMergeUuid(mergeUuid);

    ctx.body = new Result(scoreList);
  }

  async saveManualOperation() {
    // 参数包括 3 大部分 uuid、基础信息、答案分数
    // questionnaireUuid、mergeUuid
    // 基础信息
    // 分数
    const { ctx } = this;

    ctx.validate({
      questionnaireUuid: uuidCommonRule,
      mergeUuid: {
        required: false,
        ...uuidCommonRule
      },
      tel: {
        type: 'string'
      },
      gender: {
        type: 'enum',
        values: [1, 2],
        convertType: 'number'
      },
      maritalStatus: {
        type: 'enum',
        values: [0, 1],
        convertType: 'number'
      },
      childrenSituation: {
        type: 'enum',
        values: [0, 1],
        convertType: 'number'
      },
      age: {
        type: 'enum',
        values: [1, 2, 3, 4],
        convertType: 'number'
      },
      education: {
        type: 'enum',
        values: [1, 2, 3, 4],
        convertType: 'number'
      },
      score: {
        type: 'array',
        itemType: 'number',
        min: TOTAL_QUESTION,
        max: TOTAL_QUESTION
      },
      email: {
        type: 'string',
        required: false,
      }
    }, ctx.request.body);

    const {
      questionnaireUuid,
      name,
      num,
      jobPosition,
      affiliated,
      workUnit,
      operatingPost
    } = ctx.request.body;

    const {
      userNameVisible,
      userNumVisible,
      jobPositionVisible,
      affiliatedVisible,
      workUnitVisible,
      operatingPostVisible
    } = await ctx
      .service
      .questionnaire
      .findQuestionnaireByUuid(questionnaireUuid);

    const rule: {
      jobPosition?: { type: string },
      affiliated?: { type: string },
      workUnit?: { type: string },
      operatingPost?: { type: string },
      name?: { type: string },
      num?: { type: string }
    } = {};

    if (userNameVisible) {
      rule.name = { type: 'string' };
    }

    if (userNumVisible) {
      rule.num = { type: 'string' };
    }

    if (jobPositionVisible) {
      rule.jobPosition = { type: 'string' };
    }

    if (affiliatedVisible) {
      rule.affiliated = { type: 'string' };
    }

    if (workUnitVisible) {
      rule.workUnit = { type: 'string' };
    }

    if (operatingPostVisible) {
      rule.operatingPost = { type: 'string' };
    }

    ctx.validate(rule, ctx.request.body);

    if (
      !userNameVisible
      && name
    ) {
      ctx.status = 422;
      ctx.body = new Result(undefined, '不应存在姓名！');
      return;
    }

    if (
      !userNumVisible
      && num
    ) {
      ctx.status = 422;
      ctx.body = new Result(undefined, '不应存在工号！');
      return;
    }

    if (
      !jobPositionVisible
      && jobPosition
    ) {
      ctx.status = 422;
      ctx.body = new Result(undefined, '不应存在工作职位！');
      return;
    }

    if (
      !affiliatedVisible
      && affiliated
    ) {
      ctx.status = 422;
      ctx.body = new Result(undefined, '不应存在附属单位！');
      return;
    }

    if (
      !workUnitVisible
      && workUnit
    ) {
      ctx.status = 422;
      ctx.body = new Result(undefined, '不应存在工作单位！');
      return;
    }

    if (
      !operatingPostVisible
      && operatingPost
    ) {
      ctx.status = 422;
      ctx.body = new Result(undefined, '不应存在工作岗位！');
      return;
    }

    const answerParams = ctx.request.body;

    const res = await ctx.service.answer.saveAnswer(answerParams);

    if (!res) {
      ctx.status = 500;
      ctx.body = new Result(undefined);
    }
    ctx.body = new Result(res);
  }
}

export default AnswerController;
